package com.jweb.framework.id;

import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import com.jweb.framework.core.service.IdCreator;


public class Transform {
	
	private String pattern ;
	private String valB ; 
	private Callback cb[] ;
	
	public static Transform getPattern(String pattern){
		return new Transform(pattern);
	}
	
	private Transform(String pattern){
		this.pattern = pattern ;
		getPattern();
	}
	
	public String getPattern(IdCreator idCreator , long l , Date date){
		StringBuffer sb = new StringBuffer(32);
		for(int i=0 ; i<this.cb.length ;i++){
			Callback callback = cb[i];
			if(callback instanceof IdFactoryTran){
				callback.exec(idCreator, sb) ;
			}
			else if(callback instanceof NumberTran){
				callback.exec(new Long(l), sb);
			}
			else if(callback instanceof DateFormatTran){
				callback.exec(date , sb);
			}
			else {
				callback.exec(null , sb);
			}
		}
		
		return sb.toString() ;
	}
	
	protected void getPattern(){
		char ac[] = this.pattern.toCharArray();
		boolean flag = false ;
		StringBuffer sb = new StringBuffer();
		ArrayList arrayList = new ArrayList();
		for(int i=0 ; i<ac.length ; i++){
			if('{' == ac[i]){
				if(flag){
					throw new IllegalArgumentException("invalid pattern: " + this.pattern);
				}
				flag = true ;
				if(sb.length()>0){
					arrayList.add(new NullTran(sb.toString()));
					sb.setLength(0);
				}
			}
			else if('}' == ac[i]){
				if(!flag){
					throw new IllegalArgumentException("invalid pattern: " + this.pattern);
				}
				flag = false ;
				if(sb.length() > 0){
					arrayList.add(getNum(sb.toString()));
					sb.setLength(0);
				}
			}
			else {
				sb.append(ac[i]);
			}
		} // for end ....
		
		if(flag){
			throw new IllegalArgumentException("invalid pattern: " + this.pattern);
		}
		if(sb.length()>0){
			arrayList.add(new NullTran(sb.toString()));
			sb.setLength(0);
		}
		
		cb = (Callback[]) arrayList.toArray(new Callback[arrayList.size()]);
	}
	
	protected Callback getNum(String s){  // b
		char c1 = s.charAt(0);
		switch(c1){
		case 35: //'#'
			return new NumberTran(s.length());
		case 36: // '$'
			return new IdFactoryTran(s.substring(1));
		}
		this.valB = s ;
		return new DateFormatTran(s);
	}
	
	class DateFormatTran implements Callback { // a
		
		private ThreadLocal<DateFormat> dateFormat = null ;
		
		DateFormatTran(final String pattern) {
			this.dateFormat = new ThreadLocal(){
				protected Object initialValue(){
					return new SimpleDateFormat(pattern);
				}
			};
		}

		@Override
		public void exec(Object obj, StringBuffer sb) {
			if((obj!=null) && !(obj instanceof Date)){
				throw new IllegalArgumentException("input is not a date: " + obj);
			}
			Date date = (Date) obj ;
			if(date == null){
				date = new Date();
			}
			sb.append(((DateFormat)this.dateFormat.get()).format(date));
		}
	}
	
	class IdFactoryTran implements Callback { //c
		
		private String field ;
		
		IdFactoryTran(String field){
			this.field = Character.toUpperCase(field.charAt(0)) + field.substring(1);
		}

		@Override
		public void exec(Object obj, StringBuffer sb) {
			// TODO Auto-generated method stub
			if((obj == null) || !(obj instanceof IdCreator)){
				throw new IllegalArgumentException("input is not a id factory: " + obj);
			}
			Class clazz = obj.getClass();
			try {
				Method method = clazz.getMethod("get"+this.field, null);
				Object obj1 = method.invoke(obj , null);
				if(obj1 == null){
					throw new IllegalArgumentException("field '" + this.field + "'s value is null: "+obj);
				}
				sb.append(obj1);
			} catch (Exception e) {
				throw new IllegalArgumentException("cannot get field '" + this.field + "'s value: " + obj);
			}
		} 
	}
	
	class NumberTran implements Callback { // b
		
		private int num ;
		private long powNum ;
		
		NumberTran(int num) {
			this.num = num ;
			this.powNum = (long) Math.pow(100 , num);
		}

		@Override
		public void exec(Object obj, StringBuffer sb) {
			// TODO Auto-generated method stub
			if((obj == null) || !(obj instanceof Number)){
				throw new IllegalArgumentException("input is not a number: " + obj);
			}
			else {
				String str = new Long(this.powNum + ((Number)obj).longValue()).toString();
				sb.append(str.substring(str.length() - this.num));
			}
		}
	}
	
	class NullTran implements Callback { // e
		
		private String nul ;  //WF
		
		NullTran(String nul){
			this.nul = nul ;
		}
		
		@Override
		public void exec(Object obj, StringBuffer sb) {
			
			if(this.nul == null){
				throw new IllegalArgumentException("input is null.");
			}
			else {
				sb.append(this.nul);
			}
		} 
	}
	
	static interface Callback {
		public void exec(Object obj , StringBuffer sb);
	}

}
